package com.lzh.seatrend.config.datasource;


import com.github.pagehelper.PageInterceptor;
import com.lzh.seatrend.util.seatrend.AesUtil;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * basePackages属性表明接口类所在的包，
 * sqlSessionTemplateRef表明接口类使用的SqlSessionTemplate
 */

@Configuration
//@MapperScan(basePackages = {"com.lzh.springsecurity.mapper"}, sqlSessionTemplateRef = "sqlSessionTemplate")
public class MybatisConfig {

    Logger logger = LoggerFactory.getLogger(MybatisConfig.class);

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.maximum-pool-size}")
    private int maximumPoolSize;
    @Value("${spring.datasource.max-idle}")
    private int maxIdle;
    @Value("${spring.datasource.min-idle}")
    private int minIdle;
    @Value("${spring.datasource.initial-size}")
    private int initialSize;
    @Value("${spring.datasource.validation.query}")
    private String validationQuery;
    @Value("${spring.datasource.test-on-borrow}")
    private boolean testOnBorrow;
    @Value("${spring.datasource.test-while-idle}")
    private boolean testWhileIdle;
    @Value("${spring.datasource.time-between-eviction-runs-millis}")
    private long timeBetweenEvictionRunsMillis;
    @Value("${spring.datasource.max-wait}")
    private long maxWait;

    /**
     * 数据库连接池配置
     *
     * @return
     * @Primary 设置多实现类的默认调用
     */
    @Bean(name = "dataSource")
    @Primary
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName(driverClassName);
        try {
            if (BaseConfig.IS_ENCRYPT_DATA) {
                url = AesUtil.decrypt(url, BaseConfig.ENCRYPT_KEY);
                username = AesUtil.decrypt(username, BaseConfig.ENCRYPT_KEY);
                password = AesUtil.decrypt(password, BaseConfig.ENCRYPT_KEY);
            }
        } catch (Exception e) {
            e.printStackTrace();
            url = "";
            username = "";
            password = "";
        }
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        ds.setMaxTotal(maximumPoolSize);
        ds.setValidationQuery(validationQuery);
        ds.setInitialSize(initialSize);
        ds.setMaxIdle(maxIdle);
        ds.setMinIdle(minIdle);
        ds.setTestOnBorrow(testOnBorrow);
        ds.setTestWhileIdle(testWhileIdle);
        ds.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        ds.setMaxWaitMillis(maxWait);
        return ds;
    }

    /**
     * Mybatis可以配置多个环境，每个sqlSessionFactory实例只能对应一种环境，相当于一个数据库连接对应
     * 一个SqlSessionFacory实例
     *
     * @param dataSource
     * @return
     */
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("dataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        //1.数据源配置
        bean.setDataSource(dataSource);

        //2.分页插件配置
        PageInterceptor pageInterceptor = new PageInterceptor();
        Properties properties = new Properties();
        /**
         *         分页合理化参数，默认值为 false 。
         *         当该参数设置为 true 时， pageNum<=0 时会查询第一页， pageNum>pages （超过总数时），会查询最后一页。
         *         默认 false 时，直接根据参数进行查询。
         */
        properties.setProperty("reasonable", "true");
        /**
         *  自动分页的配合，默认为false
         *  设置为true时，支持通过 Mapper 接口参数来传递分页参数，
         *  依据params配置的字段中取值，找到合适的值后就会自动配置分页。（默认是pageNum,pageSize）
         */
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("params", "pageNum=page;pageSize=size");
        properties.setProperty("returnPageInfo", "true");
        /**
         * 为了支持startPage(Object params) ，增加了该参数来配置参数映射
         * 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;
         * reasonable=reasonable;pageSizeZero=pageSizeZero
         */
        properties.setProperty("params", "count=countSql");
        pageInterceptor.setProperties(properties);
        //添加插件
        bean.setPlugins(new Interceptor[]{pageInterceptor});

        //3.配置mapper
        bean.setMapperLocations(resolveMapperLocations());
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setConfigLocation(resolver.getResource("classpath:mybatis-config.xml"));
        } catch (Exception e) {
            logger.error("Get Mybatis-Config Resources Happened Exception",e);
        }

        return bean.getObject();
//        //添加XML目录
//        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//        //重构配置多个mapper路径
//        List<String> mapperLocations = new ArrayList<>();
//        mapperLocations.add("classpath:mapper/*.xml");
//        mapperLocations.add("classpath:learnmapper/*.xml");
//        List<Resource> resources = new ArrayList<>();
//        try {
//            bean.setMapperLocations(resolver.getResources(mapperLocations));
//            bean.setConfigLocation(resolver.getResource("classpath:mybatis-config.xml"));
//            return bean.getObject();
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new RuntimeException();
//        }
//                    return bean.getObject();
    }

    public Resource[] resolveMapperLocations() {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        List<String> mapperLocations = new ArrayList<>();
        List<Resource> resources = new ArrayList<>();
        //TODO 改成动态配置?
        mapperLocations.add("classpath:mapper/*.xml");
        mapperLocations.add("classpath:learnmapper/*.xml");
        if (!CollectionUtils.isEmpty(mapperLocations)) {
            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] resolverMappers = resolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(resolverMappers));
                } catch (IOException e) {
                    logger.error("Get Mybatis Resources Happened Exception", e);
                }
            }
        }
        return resources.toArray(new Resource[resources.size()]);
    }

    @Bean(name = "transactionManager")
    @Primary
    public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "sqlSessionTemplate")
    @Primary
    public SqlSessionTemplate defaultSqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
